package nkr1pt.popkorn.properties;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import nkr1pt.popkorn.events.PopkornEvent;
import nkr1pt.popkorn.events.EventBus;
import nkr1pt.popkorn.events.EventObserver;
import nkr1pt.popkorn.exceptions.UnrecoverableException;
import nkr1pt.popkorn.helper.FileUtils;
import org.apache.commons.lang.StringUtils;

/**
 *
 * @author Kristof Vanhaeren
 */
@Singleton
public class PropertyLoader implements EventObserver {

    private static final String POPKORN_PROPERTIES = "popkorn.properties";
    private PopkornProperties popkornProperties;
    private PopkornProperties oldPopkornProperties;
    private static final Logger logger = Logger.getLogger(PropertyLoader.class.getName());

    @Inject
    public PropertyLoader(EventBus eventBus) {
        eventBus.subscribe(this, PopkornEvent.EventType.PROPERTYFILE_CHANGED);
        eventBus.addEventPriorityBinding(PopkornEvent.EventType.PROPERTYFILE_CHANGED, this, 1);
    }

    public PopkornProperties getProperties() {
        if (popkornProperties != null) {
            return popkornProperties;
        }

        loadPopkornProperties();
        return popkornProperties;

    }

    public void setProperties(PopkornProperties popkornProperties) {
        this.popkornProperties = popkornProperties;
    }

    private void loadPopkornProperties() {
        if (popkornProperties != null) {
            oldPopkornProperties = (PopkornProperties)popkornProperties.clone();
        }

        try {
            Properties props = new Properties();
            props.load(new FileInputStream(getPropertiesFile()));
            popkornProperties = new PopkornProperties();
            popkornProperties.setDownloadCandidates(props.getProperty(PopkornPropertiesEnum.DOWNLOADCANDIDATES.getPropertyKey()));
            popkornProperties.setDownloadInProgress(props.getProperty(PopkornPropertiesEnum.DOWNLOADINPROGRESS.getPropertyKey()));
            popkornProperties.setDownloadCompleted(props.getProperty(PopkornPropertiesEnum.DOWNLOADCOMPLETED.getPropertyKey()));
            popkornProperties.setDownloadFailed(props.getProperty(PopkornPropertiesEnum.DOWNLOADFAILED.getPropertyKey()));
            popkornProperties.setExtractionFailed(props.getProperty(PopkornPropertiesEnum.EXTRACTIONFAILED.getPropertyKey()));
            popkornProperties.setRapidshareLogin(props.getProperty(PopkornPropertiesEnum.RAPIDSHARELOGIN.getPropertyKey()));
            popkornProperties.setRapidsharePassword(props.getProperty(PopkornPropertiesEnum.RAPIDSHAREPASSWORD.getPropertyKey()));
            popkornProperties.setScheduler(props.getProperty(PopkornPropertiesEnum.SCHEDULER.getPropertyKey()));
            popkornProperties.setKeystorePassword(props.getProperty(PopkornPropertiesEnum.KEYSTOREPASSWORD.getPropertyKey()));

            PopkornPropertiesValidator validator = new PopkornPropertiesValidator();
            validator.validate(popkornProperties);
            logger.log(Level.INFO, POPKORN_PROPERTIES + " are loaded.");
        } catch (Exception ex) {
            if (oldPopkornProperties != null) {
                logger.log(Level.INFO, "Reusing original " + POPKORN_PROPERTIES);
                popkornProperties = oldPopkornProperties;
            } else {
                throw new UnrecoverableException("Properties could not be loaded.\n" + ex.getMessage());
            }
        }
    }

    public File getPropertiesFile() {
        File file = new File(getApplicationProperties().getProperty("location.properties"));
        if (!FileUtils.isAccessable(file)) {
            throw new UnrecoverableException("Properties could not be loaded. Please verify that the file '" + getApplicationProperties().getProperty("location.properties") + "' exists.");
        }

        return file;
    }

    private Properties getApplicationProperties() {
        try {
            Properties props = new Properties();
            props.load(ClassLoader.getSystemResourceAsStream(POPKORN_PROPERTIES));
            return props;
        } catch (IOException ex) {
            throw new UnrecoverableException("Application specific properties could not be loaded; this should never happen!\n" + ex.getMessage());
        }
    }

    public void handleEvent(PopkornEvent event) {
        loadPopkornProperties();
    }

    private class PopkornPropertiesValidator {

        private Set<String> invalidProperties = new HashSet<String>();

        public boolean validate(PopkornProperties properties) {
            if (StringUtils.isEmpty(properties.getDownloadCandidates())) {
                invalidProperties.add(PopkornPropertiesEnum.DOWNLOADCANDIDATES.getPropertyKey());
            }
            if (StringUtils.isEmpty(properties.getDownloadInProgress())) {
                invalidProperties.add(PopkornPropertiesEnum.DOWNLOADINPROGRESS.getPropertyKey());
            }
            if (StringUtils.isEmpty(properties.getDownloadCompleted())) {
                invalidProperties.add(PopkornPropertiesEnum.DOWNLOADCOMPLETED.getPropertyKey());
            }
            if (StringUtils.isEmpty(properties.getDownloadFailed())) {
                invalidProperties.add(PopkornPropertiesEnum.DOWNLOADFAILED.getPropertyKey());
            }
            if (StringUtils.isEmpty(properties.getExtractionFailed())) {
                invalidProperties.add(PopkornPropertiesEnum.EXTRACTIONFAILED.getPropertyKey());
            }
            if (StringUtils.isEmpty(properties.getRapidshareLogin())) {
                invalidProperties.add(PopkornPropertiesEnum.RAPIDSHARELOGIN.getPropertyKey());
            }
            if (StringUtils.isEmpty(properties.getRapidsharePassword())) {
                invalidProperties.add(PopkornPropertiesEnum.RAPIDSHAREPASSWORD.getPropertyKey());
            }
            if (StringUtils.isEmpty(properties.getScheduler())) {
                invalidProperties.add(PopkornPropertiesEnum.SCHEDULER.getPropertyKey());
            }
            if (StringUtils.isEmpty(properties.getKeystorePassword())) {
                invalidProperties.add(PopkornPropertiesEnum.KEYSTOREPASSWORD.getPropertyKey());
            }

            if (invalidProperties.size() > 0) {
                throw new UnrecoverableException(POPKORN_PROPERTIES + " is invalid. Missing properties " + invalidProperties);
            }

            return true;
        }
    }
}